/*
 * Copyright 2007 Jaisy Sprl.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package be.jaisy.ui.gwt.widget.client.viewer.table.internal;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import be.jaisy.ui.gwt.widget.client.viewer.ContentViewer;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.ui.AbstractImagePrototype;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.ImageBundle;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.TreeImages;
import com.google.gwt.user.client.ui.Widget;

/**
 * Helper class for storting
 * 
 * @author Stany Blanvalet <stany.blanvalet@jaisy.be>
 */
public class SortableHeaderTableViewer{

	/**
	 * An image provider to make available images to Bundle.
	 */
	public interface Images extends ImageBundle, TreeImages {
		AbstractImagePrototype asc();

		AbstractImagePrototype desc();

		AbstractImagePrototype blank();
	}

	
	private static final int HEADER_ROW_INDEX = 0;
	
	private static final String HEADER_ROW_STYLE = "-header";
	
	private static final String SORTABLE_CELL_STYLE = "-sortable";
	
	private static final int SORT_DIRECTION_NONE = 0;

	private static final int SORT_DIRECTION_ASC = 1;

	private static final int SORT_DIRECTION_DESC = 2;

	private static final int SORT_DIRECTION_DEFAULT = SORT_DIRECTION_ASC;

	/**
	 * This viewer's comparator used for sorting.
	 */
	private TableViewerComparator sorter = new TableViewerComparator();

	/**
	 * A map from the viewer's header elements to String/widget. key type: columnIndex <code>Integer</code> value type:
	 * <code>HtmlHeader</code>.
	 */
	private Map/* <Integer, HtmlHeader> */headerMap;

	protected int sortedColumnIndex = -1;

	protected int sortedDirection = SORT_DIRECTION_DEFAULT;

	private ContentViewer contentViewer;

	public SortableHeaderTableViewer(ContentViewer contentViewer){
		super();
		this.contentViewer = contentViewer;
	}

	public void addHeader(int columnIndex, String name){
		addHeader(columnIndex, name, false);
	}

	public void addHeader(int columnIndex, String name, boolean sortable){
		if (this.headerMap == null){
			this.headerMap = new HashMap/* <Integrer, HtmlHeader> */();
		}
		HtmlHeader htmlHeader = new HtmlHeader(columnIndex, name, sortable);
		this.headerMap.put(new Integer(columnIndex), htmlHeader);
	}

	/**
	 * This method is reponsible for the eader row creation
	 * 
	 * @param tableCellProvider
	 *           provide method impl to adapt real table.
	 */
	public void provideFilters(ITableCellProvider tableCellProvider){
		for (Iterator iter = headerMap.entrySet().iterator(); iter.hasNext();){
			Entry entry = (Entry)iter.next();
			Integer key = (Integer)entry.getKey();
			HtmlHeader value = (HtmlHeader)entry.getValue();
			tableCellProvider.provideData(HEADER_ROW_INDEX, key.intValue(), value.getHtlm());
			tableCellProvider.provideStyle(HEADER_ROW_INDEX, HEADER_ROW_STYLE);
			if(value.isSortable())
				tableCellProvider.provideStyle(HEADER_ROW_INDEX, key.intValue(), SORTABLE_CELL_STYLE);
		}
	}

	public void activateSort(int columnIndex){
		if (this.sortedColumnIndex == columnIndex){
			if (sortedDirection == SORT_DIRECTION_ASC)
				sortedDirection = SORT_DIRECTION_DESC;
			else
				sortedDirection = SORT_DIRECTION_ASC;
		}
		else{
			sortedDirection = SORT_DIRECTION_ASC;
			this.sortedColumnIndex = columnIndex;
		}
		this.contentViewer.refresh();
	}

	/**
	 * Returns the result of running the given elements through the filters.
	 * 
	 * @param elements
	 *           the elements to filter
	 * @return only the elements which all filters accept
	 */
	public Object[] sort(Object[] elements){
		if(!hasSorters())
			return elements;
		if (this.sortedDirection == SORT_DIRECTION_ASC)
			sorter.sort(contentViewer, elements, this.sortedColumnIndex);
		else if (this.sortedDirection == SORT_DIRECTION_DESC)
			sorter.unsort(contentViewer, elements, this.sortedColumnIndex);
		return elements;
	}

	/**
	 * Returns whether this viewer has any sorters.
	 * 
	 * @return boolean
	 */
	public boolean hasSorters(){
		return this.sortedColumnIndex != -1 && this.sortedDirection != SORT_DIRECTION_NONE;
	}

	private class HtmlHeader{
	
		private boolean isSortable = false;

		private String name;

		protected int columnIndex = -1;

		public HtmlHeader(int columnIndex, String name){
			super();
			this.columnIndex = columnIndex;
			this.name = name;
		}

		public HtmlHeader(int columnIndex, String name, boolean isSortable){
			this(columnIndex, name);
			this.isSortable = isSortable;
		}

		public Widget getHtlm(){
			HorizontalPanel panel = new HorizontalPanel();
			panel.setWidth("100%");
			Label label = new Label(name);
			label.setWidth("100%");
			label.addStyleName("-readonly");
			panel.add(label);
			if (isSortable){
				ClickListener listener = new ClickListener(){

					public void onClick(Widget sender){
						activateSort(columnIndex);
					}
				};				
				label.addClickListener(listener);
				if (sortedColumnIndex == columnIndex && sortedDirection == SORT_DIRECTION_ASC){
					Image image = ((Images) GWT.create(Images.class)).asc().createImage();
					image.addClickListener(listener);
					panel.add(image);
				}
				else if (sortedColumnIndex == columnIndex && sortedDirection == SORT_DIRECTION_DESC){
					Image image = ((Images) GWT.create(Images.class)).desc().createImage();
					image.addClickListener(listener);
					panel.add(image);
					
				}else{
					Image image = ((Images) GWT.create(Images.class)).blank().createImage();
					image.addClickListener(listener);
					panel.add(image);					
				}
			}

			return panel;
		}
		
		public boolean isSortable(){
			return isSortable;
		}
	}
}